#    This file is part of robo-ircbot.
#
#    robo-ircbot is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    robo-ircbot is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with robo-ircbot.  If not, see <http://www.gnu.org/licenses/>.

package Robo::EventHandler;
use strict;
use warnings;
use Robo::Event;

# Constructor
sub new
{
        my ($class, $robo, $cfg, $sock, $mod) = @_;
        
        my $self = { };
        
        $self->{robo} = $robo;
        $self->{cfg} = $cfg;
        $self->{sock} = $sock;
        $self->{mod} = $mod;
        $self->{last_message} = time();
        
        $SIG{'ALRM'} = sub {
                # If 4 minutes has gone by without any messages from the server,
                # we will assume that we have timed out.  Close the socket.
                if ((time() - $self->{last_message}) >= 240 && $self->{sock}) {
                        $self->{robo}->log("Timed out! Closing socket!");
                        close($self->{sock});
                        $self->{robo}->{irc}->irc_connect();
                }
                
                # Signal an alarm in another 30 seconds.
                alarm(60);
        };
        
        # This will start the infinite alarm loop that checks for timeouts.
        alarm(60);
        
        bless($self);
        return $self;
}

# Send event to handlers.
sub send_to_handlers
{
        my ($self, $event, $name) = @_;
        
        foreach (@{$self->{mod}->{events}->{$name}}) {
                next unless (defined($_) && length($_) > 3);
                eval("\$self->{mod}->{call}->{\$_}->event_".$name."(\$event)");
                if ($@) { chomp($@); $self->{robo}->log($_.": ".$@); }
        }
}

# Look for events and send them out to modules accordingly.
sub event_loop
{
        my $self = shift;
        
        # Loop while the socket is connected.
        my $sock = $self->{sock};
        while (<$sock>) {
                my $data = $_;
                $self->{last_message} = time();
                
                # Double choppa, removes \r\n from string.
                chop($data); chop($data);
                
                # Hashref holding everything a script might need.
                my $event = Robo::Event->new(
                        sock => $sock,
                        cfg => $self->{cfg},
                        robo => $self->{robo},
                        from => undef,
                        to => undef,
                        data => undef,
                        raw => undef,
                        knick => undef,
                );
                
                # RAW
                if ($data =~ /^:(\S+) (\d+) (\S+) :(.+)/ ||
                        $data =~ /^:(\S+) (\d+) \* (\S+) :(.+)/) {
                        $event->from($1);
                        $event->raw($2);
                        $event->to($3);
                        $event->data($4);
                        
                        $self->send_to_handlers($event, "raw");
                # SNOTICE
                } elsif ($data =~ /^NOTICE (\S+) :(.+)/) {
                        $event->to($1);
                        $event->data($2);
                        
                        $self->send_to_handlers($event, "snotice");
                # PRIVMSG
                } elsif ($data =~ /^:(\S+) PRIVMSG (\S+) :(.+)$/) {
                        $event->from($1);
                        $event->to($2);
                        $event->data($3);
                        
                        $self->send_to_handlers($event, "privmsg");
                # PING
                } elsif ($data =~ /^PING (.+)/) {
                        $event->data($1);
                        
                        $self->send_to_handlers($event, "ping");
                # NOTICE
                } elsif ($data =~ /^:(\S+) NOTICE (\S+) :(.+)/) {
                        $event->from($1);
                        $event->to($2);
                        $event->data($3);
                        
                        $self->send_to_handlers($event, "notice");
                # PART
                } elsif ($data =~ /^:(\S+) PART (\S+)( :(.*))?/) {
                        $event->from($1);
                        $event->to($2);
                        $event->data($4);
                        
                        $self->send_to_handlers($event, "part");
                # JOIN
                } elsif ($data =~ /^:(\S+) JOIN :?(.+)/) {
                        $event->from($1);
                        $event->to($2);
                        
                        $self->send_to_handlers($event, "join");
                # QUIT
                } elsif ($data =~ /^:(\S+) QUIT :(.+)/) {
                        $event->from($1);
                        $event->data($2);
                        
                        $self->send_to_handlers($event, "quit");
                # KICK
                } elsif ($data =~ /^:(\S+) KICK (\S+) (\S+) :(.+)/) {
                        $event->from($1);
                        $event->to($2);
                        $event->knick($3);
                        $event->data($4);
                        
                        $self->send_to_handlers($event, "kick");
                }
                
                # Log raw data if no module wanted us to skip this.
                if (!$event->nolog) {
                        $self->{robo}->log($data);
                }
        }
        
        close($self->{sock});
}

1;
